#include "stdafx.h"
#include "base/window/window_utils.h"

struct StyleInfo {
    int m_nFlag;
    int m_nCode;
    const TCHAR *m_pName;
};

StyleInfo s_vStyleList[] = {
    { SF_WS_BORDER, WS_BORDER, _T("WS_BORDER") },
    { SF_WS_CAPTION, WS_CAPTION, _T("WS_CAPTION") },
    { SF_WS_CHILD, WS_CHILD, _T("WS_CHILD") },
    { SF_WS_CHILDWINDOW, WS_CHILDWINDOW, _T("WS_CHILDWINDOW") },
    { SF_WS_CLIPCHILDREN, WS_CLIPCHILDREN, _T("WS_CLIPCHILDREN") },
    { SF_WS_CLIPSIBLINGS, WS_CLIPSIBLINGS, _T("WS_CLIPSIBLINGS") },
    { SF_WS_DISABLED, WS_DISABLED, _T("WS_DISABLED") },
    { SF_WS_DLGFRAME, WS_DLGFRAME, _T("WS_DLGFRAME") },
    { SF_WS_GROUP, WS_GROUP, _T("WS_GROUP") },
    { SF_WS_HSCROLL, WS_HSCROLL, _T("WS_HSCROLL") },
    { SF_WS_ICONIC, WS_ICONIC, _T("WS_ICONIC") },
    { SF_WS_MAXIMIZE, WS_MAXIMIZE, _T("WS_MAXIMIZE") },
    { SF_WS_MAXIMIZEBOX, WS_MAXIMIZEBOX, _T("WS_MAXIMIZEBOX") },
    { SF_WS_MINIMIZE, WS_MINIMIZE, _T("WS_MINIMIZE") },
    { SF_WS_MINIMIZEBOX, WS_MINIMIZEBOX, _T("WS_MINIMIZEBOX") },
    { SF_WS_OVERLAPPED, WS_OVERLAPPED, _T("WS_OVERLAPPED") },
    { SF_WS_OVERLAPPEDWINDOW, WS_OVERLAPPEDWINDOW, _T("WS_OVERLAPPEDWINDOW") },
    { SF_WS_POPUP, WS_POPUP, _T("WS_POPUP") },
    { SF_WS_POPUPWINDOW, WS_POPUPWINDOW, _T("WS_POPUPWINDOW") },
    { SF_WS_SIZEBOX, WS_SIZEBOX, _T("WS_SIZEBOX") },
    { SF_WS_SYSMENU, WS_SYSMENU, _T("WS_SYSMENU") },
    { SF_WS_TABSTOP, WS_TABSTOP, _T("WS_TABSTOP") },
    { SF_WS_THICKFRAME, WS_THICKFRAME, _T("WS_THICKFRAME") },
    { SF_WS_TILED, WS_TILED, _T("WS_TILED") },
    { SF_WS_TILEDWINDOW, WS_TILEDWINDOW, _T("WS_TILEDWINDOW") },
    { SF_WS_VISIBLE, WS_VISIBLE, _T("WS_VISIBLE") },
    { SF_WS_VSCROLL, WS_VSCROLL, _T("WS_VSCROLL") },
};

StyleInfo s_vExStyleList[] = {
    { ESF_WS_EX_ACCEPTFILES, WS_EX_ACCEPTFILES, _T("WS_EX_ACCEPTFILES") },
    { ESF_WS_EX_APPWINDOW, WS_EX_APPWINDOW, _T("WS_EX_APPWINDOW") },
    { ESF_WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE, _T("WS_EX_CLIENTEDGE") },
    { ESF_WS_EX_COMPOSITED, WS_EX_COMPOSITED, _T("WS_EX_COMPOSITED") },
    { ESF_WS_EX_CONTEXTHELP, WS_EX_CONTEXTHELP, _T("WS_EX_CONTEXTHELP") },
    { ESF_WS_EX_CONTROLPARENT, WS_EX_CONTROLPARENT, _T("WS_EX_CONTROLPARENT") },
    { ESF_WS_EX_DLGMODALFRAME, WS_EX_DLGMODALFRAME, _T("WS_EX_DLGMODALFRAME") },
    { ESF_WS_EX_LAYERED, WS_EX_LAYERED, _T("WS_EX_LAYERED") },
    { ESF_WS_EX_LAYOUTRTL, WS_EX_LAYOUTRTL, _T("WS_EX_LAYOUTRTL") },
    { ESF_WS_EX_LEFT, WS_EX_LEFT, _T("WS_EX_LEFT") },
    { ESF_WS_EX_LEFTSCROLLBAR, WS_EX_LEFTSCROLLBAR, _T("WS_EX_LEFTSCROLLBAR") },
    { ESF_WS_EX_LTRREADING, WS_EX_LTRREADING, _T("WS_EX_LTRREADING") },
    { ESF_WS_EX_MDICHILD, WS_EX_MDICHILD, _T("WS_EX_MDICHILD") },
    { ESF_WS_EX_NOACTIVATE, WS_EX_NOACTIVATE, _T("WS_EX_NOACTIVATE") },
    { ESF_WS_EX_NOINHERITLAYOUT, WS_EX_NOINHERITLAYOUT, _T("WS_EX_NOINHERITLAYOUT") },
    { ESF_WS_EX_NOPARENTNOTIFY, WS_EX_NOPARENTNOTIFY, _T("WS_EX_NOPARENTNOTIFY") },
    { ESF_WS_EX_OVERLAPPEDWINDOW, WS_EX_OVERLAPPEDWINDOW, _T("WS_EX_OVERLAPPEDWINDOW") },
    { ESF_WS_EX_PALETTEWINDOW, WS_EX_PALETTEWINDOW, _T("WS_EX_PALETTEWINDOW") },
    { ESF_WS_EX_RIGHT, WS_EX_RIGHT, _T("WS_EX_RIGHT") },
    { ESF_WS_EX_RIGHTSCROLLBAR, WS_EX_RIGHTSCROLLBAR, _T("WS_EX_RIGHTSCROLLBAR") },
    { ESF_WS_EX_RTLREADING, WS_EX_RTLREADING, _T("WS_EX_RTLREADING") },
    { ESF_WS_EX_STATICEDGE, WS_EX_STATICEDGE, _T("WS_EX_STATICEDGE") },
    { ESF_WS_EX_TOOLWINDOW, WS_EX_TOOLWINDOW, _T("WS_EX_TOOLWINDOW") },
    { ESF_WS_EX_TOPMOST, WS_EX_TOPMOST, _T("WS_EX_TOPMOST") },
    { ESF_WS_EX_TRANSPARENT, WS_EX_TRANSPARENT, _T("WS_EX_TRANSPARENT") },
    { ESF_WS_EX_WINDOWEDGE, WS_EX_WINDOWEDGE, _T("WS_EX_WINDOWEDGE") },
};

static const TCHAR * InnerGetStyleName(int nStyleFlag, StyleInfo *pStyleList, int nListNum)
{
    if(nStyleFlag >= nListNum) {
        return _T("");
    }

    return pStyleList[nStyleFlag].m_pName;
}

static std::vector<int> InnerParseStyle(LONG nStyle, StyleInfo *pStyleList, int nListNum)
{
    std::vector<int> vStyles;
    if(0 == nStyle) {
        return vStyles;
    }

    int i = 0;
    while(i < nListNum) {
        if(0 != pStyleList[i].m_nCode && (nStyle & pStyleList[i].m_nCode) == pStyleList[i].m_nCode) {
            vStyles.push_back(pStyleList[i].m_nFlag);
        }
        ++i;
    }

    return vStyles;
}

static LONG InnerBuildStyle(int *pSFList, int nStyleCount, StyleInfo *pStyleList, int nListNum)
{
    int i = 0;
    LONG nStyle = 0;
    while(i < nStyleCount) {
        if(pSFList[i] < nListNum) {
            nStyle |= pStyleList[pSFList[i]].m_nCode;
        }
        ++i;
    }

    return nStyle;
}

static std::vector<CString> InnerGetAllStyleNames(StyleInfo *pStyleList, int nListNum)
{
    std::vector<CString> vStyleNames;

    int i = 0;
    while(i < nListNum) {
        vStyleNames.push_back(CString(pStyleList[i].m_pName));
        ++i;
    }

    return vStyleNames;
}

CString GetStyleName(int nStyleFlag)
{
    return InnerGetStyleName(nStyleFlag, s_vStyleList, SF_WS_NUM);
}

std::vector<int> ParseStyle(LONG nStyle)
{
    std::vector<int> vStyles = InnerParseStyle(nStyle, s_vStyleList, SF_WS_NUM);

    if((nStyle & 0xC0000000) == 0) {
        vStyles.push_back(SF_WS_OVERLAPPED);
    }

    return vStyles;
}

LONG BuildStyle(int *pSFList, int nStyleCount)
{
    return InnerBuildStyle(pSFList, nStyleCount, s_vStyleList, SF_WS_NUM);
}

std::vector<CString> GetAllStyleNames()
{
    return InnerGetAllStyleNames(s_vStyleList, SF_WS_NUM);
}

CString GetExStyleName(int nStyleFlag)
{
    return InnerGetStyleName(nStyleFlag, s_vExStyleList, ESF_WS_EX_NUM);
}

std::vector<int> ParseExStyle(LONG nExStyle)
{
    std::vector<int> vStyles = InnerParseStyle(nExStyle, s_vExStyleList, ESF_WS_EX_NUM);
    if((nExStyle & WS_EX_RIGHT) == 0) {
        vStyles.push_back(ESF_WS_EX_LEFT);
    }

    if((nExStyle & WS_EX_RTLREADING) == 0) {
        vStyles.push_back(ESF_WS_EX_LTRREADING);
    }

    if((nExStyle & WS_EX_LEFTSCROLLBAR) == 0) {
        vStyles.push_back(ESF_WS_EX_RIGHTSCROLLBAR);
    }

    return vStyles;
}

LONG BuildExStyle(int *pESFList, int nExStyleCount)
{
    return InnerBuildStyle(pESFList, nExStyleCount, s_vExStyleList, ESF_WS_EX_NUM);
}

std::vector<CString> GetAllExStyleNames()
{
    return InnerGetAllStyleNames(s_vExStyleList, ESF_WS_EX_NUM);
}

BOOL ClientToScreen(HWND hWnd, LPRECT lpRect)
{
    if(NULL == hWnd || NULL == lpRect) {
        return FALSE;
    }

    POINT oTopLeft = { lpRect->left, lpRect->top };
    POINT oBottomRight = { lpRect->right, lpRect->bottom };
    ::ClientToScreen(hWnd, &oTopLeft);
    ::ClientToScreen(hWnd, &oBottomRight);

    lpRect->left = oTopLeft.x;
    lpRect->top = oTopLeft.y;
    lpRect->right = oBottomRight.x;
    lpRect->bottom = oBottomRight.y;

    return TRUE;
}

BOOL ScreenToClient(HWND hWnd, LPRECT lpRect)
{
    if(NULL == hWnd || NULL == lpRect) {
        return FALSE;
    }

    POINT oTopLeft = { lpRect->left, lpRect->top };
    POINT oBottomRight = { lpRect->right, lpRect->bottom };
    ::ScreenToClient(hWnd, &oTopLeft);
    ::ScreenToClient(hWnd, &oBottomRight);

    lpRect->left = oTopLeft.x;
    lpRect->top = oTopLeft.y;
    lpRect->right = oBottomRight.x;
    lpRect->bottom = oBottomRight.y;

    return TRUE;
}

CString GetWindowClassName(HWND hWindow)
{
    CString strOutput;
    TCHAR szBuf[1024] = {0};
    ::GetClassName(hWindow, szBuf, 1023);
    strOutput.Format(_T("%s"), szBuf);
    return strOutput;
}

int MfcHotkeyModifierToSysHotkeyModifier(WORD nMfcModifier)
{
    int nSysModifier = 0;

    if(nMfcModifier & HOTKEYF_ALT) {
        nSysModifier |= MOD_ALT;
    }

    if(nMfcModifier & HOTKEYF_CONTROL) {
        nSysModifier |= MOD_CONTROL;
    }

    if(nMfcModifier & HOTKEYF_SHIFT) {
        nSysModifier |= MOD_SHIFT;
    }

    return nSysModifier;
}

WORD SysHotkeyModifierToMfcHotkeyModifier(int nSysModifier)
{
    int nMfcModifier = 0;

    if(nSysModifier & MOD_ALT) {
        nMfcModifier |= HOTKEYF_ALT;
    }

    if(nSysModifier & MOD_CONTROL) {
        nMfcModifier |= HOTKEYF_CONTROL;
    }

    if(nSysModifier & MOD_SHIFT) {
        nMfcModifier |= HOTKEYF_SHIFT;
    }

    return nMfcModifier;
}